/*
*********************************************************************************************************
*                                              Microchip PIC24FJ
*                                            Board Support Package
*
*                                                   Micrium
*                                    (c) Copyright 2005, Micrium, Weston, FL
*                                              All Rights Reserved
*
*
* File : BSP.C
* By   : Eric Shufro
*********************************************************************************************************
*/

#include <includes.h>

/*
*********************************************************************************************************
*                                         MPLAB CONFIGURATION MACROS
*********************************************************************************************************
*/

	_CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & BKBUG_ON & COE_ON & ICS_PGx1 & FWDTEN_OFF & WINDIS_OFF);                                   /* Disable the JTAG which allows use of all port A pins     */
	_CONFIG2(IESO_ON & PLLDIV_NODIV & PLL96DIS_ON & FNOSC_FRCPLL & FCKSM_CSECMD & OSCIOFNC_OFF & IOL1WAY_ON & DISUVREG_OFF & POSCMOD_XT);                   /* Select the primary (XT, HS, EC) Oscillator with PLL      */             
	_CONFIG3(WPEND_WPSTARTMEM & WPCFG_WPCFGDIS & WPDIS_WPDIS & WPFP_WPFP0);
/*
*********************************************************************************************************
*                                              VARIABLES
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                              PROTOTYPES
*********************************************************************************************************
*/
//static void BSP_PLL_Init(void);
static void Tmr_TickInit(void);
static void RP_Select(void);
static void SPI1_Init(void);
static void Set_HMC830_Mode(SPIMODE mode);
static void UART1_Init();

static USR_INT16S uart1_send_data(const USR_CHAR *dat, USR_INT08U len);

/*
*********************************************************************************************************
*                                         BSP INITIALIZATION
*
* Description : This function should be called by your application code before you make use of any of the
*               functions found in this module.
*
* Arguments   : none
*********************************************************************************************************
*/

void  BSP_Init (void)
{
//	CLKDIV = 0;
//	OSCTUN &=0b100000;
//	OSCCON |= 0x0101;

	Set_HMC830_Mode(OPENMODE);
	RP_Select();
//	LED_Init();							/* Initialize the I/Os for the LED controls                 */
    Tmr_TickInit();						/* Initialize the uC/OS-II tick interrupt                   */
	SPI1_Init();						// Initialize SPI1
	UART1_Init();						// Initialize UART1
}

/*
*********************************************************************************************************
*                                      BSP_CPU_ClkFrq()

* Description : This function determines the CPU clock frequency (Fcy)
* Returns     : The CPU frequency in (HZ)
*********************************************************************************************************
*/

USR_INT32U  BSP_CPU_ClkFrq (void)
{
    USR_INT08U   Clk_Selected;
    USR_INT16U  FRC_Div;
    USR_INT32U  CPU_Clk_Frq;


    FRC_Div       = (CLKDIV >> 8) & 0x07;                      /* Get the FRC Oscillator Divider register value            */
    FRC_Div       = (FRC_Div << 1);                               /* Compute the FRC Divider value                            */

    Clk_Selected  =  (OSCCON & COSC_MASK) >> 12;                        /* Determine which clock source is currently selected       */
    
    switch (Clk_Selected) {
        case 0:                                                         /* Fast Oscillator (FRC) Selected                           */
             CPU_Clk_Frq   =   CPU_FRC_OSC_FRQ;                         /* Return the frequency of the internal fast oscillator     */
             break;

        case 1:                                                         /* Fast Oscillator (FRC) with PLL Selected                  */
             CPU_Clk_Frq   =  (CPU_FRC_OSC_FRQ  * 4);                   /* Compute the PLL output frequency  = (FRC * 4)            */
            break;

        case 2:                                                         /* Primary External Oscillator Selected                     */
             CPU_Clk_Frq   =   CPU_PRIMARY_OSC_FRQ;                     /* Return the frequency of the primary external oscillator  */
             break;

        case 3:                                                         /* Primary External Oscillator with PLL Selected            */
             CPU_Clk_Frq   =  (CPU_PRIMARY_OSC_FRQ * 4);                /* Compute the PLL output frq as (CPU_PRIMARY_OSC_FRQ * 4)  */
             break;

        case 4:                                                         /* Secondary Oscillator Selected (SOCS)                     */
             CPU_Clk_Frq   =   CPU_SECONDARY_OSC_FRQ;                   /* Return the frq of the external secondary oscillator      */
             break;

        case 5:                                                         /* Low Power Oscillator (LPOSC) Selected                    */
             CPU_Clk_Frq   =   CPU_LPRC_OSC_FRQ;                   /* Return the frq of the Low Power Oscillator               */
             break;

        case 6:
             CPU_Clk_Frq = 0;                                           /* Return 0 for the Reserved clock setting                  */
             break;

        case 7:                                                         /* Fast Oscillator (FRC) with FRCDIV Selected               */
             CPU_Clk_Frq   =   CPU_FRC_OSC_FRQ / FRC_Div;               /* Return the clock frequency of FRC / FRC_Div              */
             break;

        default:
             CPU_Clk_Frq = 0;                                           /* Return 0 if the clock source cannot be determined        */
             break;
    }

    CPU_Clk_Frq   /=  2;                                                /* Divide the final frq by 2, get the actual CPU Frq (Fcy)  */

    return (CPU_Clk_Frq);                                               /* Return the operating frequency                           */
}

/*
*********************************************************************************************************
*                                     DISABLE ALL INTERRUPTS
*
* Description : This function disables all interrupts from the interrupt controller.
*
* Arguments   : none
*********************************************************************************************************
*/

void  BSP_IntDisAll (void)
{
	SRbits.IPL = 7;						// Disable all interrupts
}



/*
*********************************************************************************************************
*                                       TICKER INITIALIZATION
*
* Description : This function is called to initialize uC/OS-II's tick source (typically a timer generating
*               interrupts every 1 to 100 mS).
*
* Arguments   : none
*
* Note(s)     : 1) The timer operates at a frequency of Fosc / 4
*               2) The timer resets to 0 after period register match interrupt is generated
*********************************************************************************************************
*/

static  void  Tmr_TickInit (void)
{
    USR_INT32U  tmr_frq;
    USR_INT16U  cnts;

    tmr_frq   =   BSP_CPU_ClkFrq();                                     /* Get the CPU Clock Frequency (Hz) (Fcy)                    */
    cnts      =   (tmr_frq / OS_TICKS_PER_SEC) - 1;                     /* Calaculate the number of timer ticks between interrupts  */

#if BSP_OS_TMR_SEL == 2
    T2CON     =   0;                                                    /* Use Internal Osc (Fcy), 16 bit mode, prescaler = 1  		*/
    TMR2      =   0;                                                    /* Start counting from 0 and clear the prescaler count      */                                   
    PR2       =   cnts;                                                 /* Set the period register                                  */
    IPC1     &=  ~T2IP_MASK;                                            /* Clear all timer 2 interrupt priority bits                */
    IPC1     |=  (TIMER_INT_PRIO << 12);                                /* Set timer 2 to operate with an interrupt priority of 4   */
    IFS0     &=  ~T2IF;                                                 /* Clear the interrupt for timer 2                          */
    IEC0     |=   T2IE;                                                 /* Enable interrupts for timer 2                            */
    T2CON    |=   TON;                                                  /* Start the timer                                          */      
#endif

#if BSP_OS_TMR_SEL == 4
    T4CON     =   0;                                                    /* Use Internal Osc (Fcy), 16 bit mode, prescaler = 1  		*/
    TMR4      =   0;                                                    /* Start counting from 0 and clear the prescaler count      */                                   
    PR4       =   cnts;                                                 /* Set the period register                                  */
    IPC6     &=  ~T4IP_MASK;                                            /* Clear all timer 4 interrupt priority bits                */
    IPC6     |=  (TIMER_INT_PRIO << 12);                                /* Set timer 4 to operate with an interrupt priority of 4   */
    IFS1     &=  ~T4IF;                                                 /* Clear the interrupt for timer 4                          */
    IEC1     |=   T4IE;                                                 /* Enable interrupts for timer 4                            */
    T4CON    |=   TON;                                                  /* Start the timer                                          */      
#endif
}

/*
*********************************************************************************************************
*                                     OS TICK INTERRUPT SERVICE ROUTINE
*
* Description : This function handles the timer interrupt that is used to generate TICKs for uC/OS-II.
*********************************************************************************************************
*/

void OS_Tick_ISR_Handler (void) 
{
    OSTimeTick();
}

/*
*********************************************************************************************************
*                                     OS TICK INTERRUPT SERVICE ROUTINE
*
* Description : This function handles the timer interrupt that is used to generate TICKs for uC/OS-II.
*********************************************************************************************************
*/
static void RP_Select(void)
{
	UNLOCK_REG();
// set SPI_1 peripherals pin mapping
	// configure input pin
	// assign SDI1 to pin RP13
	RPINR20bits.SDI1R = 9;// rp9
	
	// configure output pin
	// assign SDO1 to pin RP1
	RPOR4bits.RP8R = 7;//rp8
	// assign SCK1 to pin RP0
	RPOR14bits.RP28R = 8;//28

// set UART_1 peripherals pin mapping
	// configure input pin
	// assign U1RX to pin RPI32
	RPINR18bits.U1RXR = 32;// RPI32
	
	// configure output pin
	// assign U1TX to pin RP31
	RPOR15bits.RP31R = 3;// RP31

	LOCK_REG();
}
/* 
* SPI commands related modules. 
* 
*/
static void SPI1_Init(void)
{
	// init the spi module for a slow (safe) clock speed first
	SPI1CON1 = 0x007c;	// Idle status high level CKP=1, see pll_operation_guide p176
						// clk edge select bit CKE=0,idle to busy/HIGH TO LOWE
						// master mode MSTEN=1
						// prescale 1:64
	SPI1CON2 = 0x0001;	// Enable Enhanced Buffer mode

	SPI1STAT = 0x8000;  // enable the peripheral
						// Interrupt when the last bit is read out from SPIxSR, now the SRXMPT = 1
						// 

	IFS0bits.SPI1IF = 0;				// clear interrupt flag
	IFS0bits.SPF1IF = 0;
} 
/* 
* SPI Send a block of data based on the length 
*/ 
USR_INT08U * SPI_Send(USR_INT08U lchannal, USR_INT08U *buf, USR_INT08U Length)
{
	USR_INT08U Dummy = 0, i = 4;
	static USR_INT08U RecBuf [4];
	
	if(buf == USR_NULL || Length == 0){
		return USR_NULL;
	}
	buf = buf + 3;
	
	switch(lchannal){
	case 1:
		SPI1_CH1_SEN = 0;
		break;
	case 2:
		break;
	}

	while(SPI1STATbits.SPITBF);		// SPITBF=0, BUF is empty
	while(Length){
		SPI1BUF = *buf;
		buf--;
		Length--;
		Dummy++;
		while(SPI1STATbits.SPITBF);		// SPITBF=0, BUF is empty
	}
	while(SPI1STATbits.SRXMPT);
	while(i > 0){
		if(!SPI1STATbits.SRXMPT){
			RecBuf[i-1] = SPI1BUF;
			i --;
		}
	}

	SPI1STATbits.SPIROV = 0;
	IFS0bits.SPI1IF = 0;				// clear interrupt flag
	IFS0bits.SPF1IF = 0;

	switch(lchannal){
	case 1:
		SPI1_CH1_SEN = 1;
		Nop();
		Nop();
		SPI1_CH1_SEN = 0;
		break;
	case 2:
		break;
	}
	
	return RecBuf;
}

/*
* SPI receives a block of data based on the length
*/
USR_INT08U SPI_Receive( USR_INT08U *buf)
{
	USR_INT08U Dummy = 0;
	
	if(SPI1STATbits.SPIROV){
		while(SPI1STATbits.SPIRBF){
			Dummy = SPI1BUF;
		}
		return -1;
	}
	if(buf == USR_NULL){
		return -1;
	}
	buf += 3;
	while(!SPI1STATbits.SPIRBF);
	{
		*buf-- = SPI1BUF;
		Dummy++;
	}
	return Dummy;
}

static void Set_HMC830_Mode(SPIMODE mode)
{
	AD1PCFGL = 0xFFFF;
	TRISB &= 0xFA2F;
	TRISA &= 0xC0FF;
//	AD1PCFGL |= 0b1u << 9;
	if(mode == OPENMODE){	// hmc830 serial port mode:open mode
		SPI1_SCK = 1;
		Nop();
		SPI1_CH1_SEN = 1;
	}
	else{					// hmc830 serial port mode:hmc mode
		SPI1_CH1_SEN = 1;
		Nop();
		SPI1_SCK = 1;
	}
}

/*
*********************************************************************************************************
*                                      		  UART_1
*********************************************************************************************************
*/

static void UART1_Init()
{
    USR_INT32U  tmr_frq;

    tmr_frq   =   BSP_CPU_ClkFrq();		/* Get the CPU Clock Frequency (Hz) (Fcy)                    */
	U1BRG = tmr_frq / 57600 / 16 - 1;
	
	IFS0bits.U1TXIF = 0;				// Clear interrupt flag
	IFS0bits.U1RXIF = 0;				// Clear interrupt flag
	U1MODE = 0x8000;					// Enable UART1
	U1STA = 0xA400;						// 

//	U1MODEbits.UARTEN = 1;				// Enable UART1
//	U1STAbits.OERR = 0;					// 
	U1STAbits.UTXEN = 1;				// Enable UART1 TX
	
//	while(U1STAbits.URXDA){
//		tmr_frq = U1RXREG;
//	}
//	IEC0bits.U1RXIE = 1;				// Enable UART1 RX interrupt
}

/*********************************************************************
 * Name        : static void echo_char(const USR_CHAR lch)
 * Function    : echo 1 character
 * PreCondition: None
 * Input       : None
 * Output      : None
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 15:50 7/8/2014
 * Note        : None
 ********************************************************************/
inline void echo_char(const USR_CHAR lch)
{
	uart1_send_data(&lch, 1);
}

/*********************************************************************
 * Name        : static inline void echo_str(const USR_CHAR *lstr, len)
 * Function    : echo 1 character
 * PreCondition: None
 * Input       : None
 * Output      : None
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 15:50 7/8/2014
 * Note        : None
 ********************************************************************/
inline void echo_str(const USR_CHAR *lstr, USR_INT08U len)
{
	uart1_send_data(lstr, len);
}

/*********************************************************************
 * Name        : static USR_INT16S uart1_send_data(const USR_CHAR *dat, USR_INT08U len)
 * Function    : send data by uart1
 * PreCondition: None
 * Input       : dat source data pointer, len data length
 * Output      : -1 error, 0 success
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 15:50 7/8/2014
 * Time/Modify : 15:50 7/8/2014
 * Note        : None
 ********************************************************************/
static USR_INT16S uart1_send_data(const USR_CHAR *dat, USR_INT08U len)
{
	if(dat == USR_NULL || len <= 0){
		return -1;
	}
	
	do{
		while(U1STAbits.UTXBF);
		U1TXREG = *dat;
		dat ++;
		len --;
	}while(len > 0);
	
	return 0;
}

/*********************************************************************
 * Name        : void adf4001_write(USR_INT32U dat)
 * Function    : send data by uart1
 * PreCondition: None
 * Input       : dat source data pointer, len data length
 * Output      : -1 error, 0 success
 * Side Effects: None
 * Author      : Lau
 * Time/Creat  : 11:49 8/28/2014
 * Time/Modify : 11:49 8/28/2014
 * Note        : None
 ********************************************************************/
void adf4001_write(USR_INT32U dat)
{
	int i;
	
	ADF4001_LE = 0;						// Load Disable
	ADF4001_CLK = 0;					// clock down
	for(i = 0; i < 24; ){
		if(dat & 0x800000){				// output data
			ADF4001_DAT = 1;
		}
		else{
			ADF4001_DAT = 0;
		}
		Nop();							// short delay
		ADF4001_CLK = 1;				// clock up
		Nop();							// short delay
		i++;
		ADF4001_CLK = 0;				// clock down
		dat = dat << 1;
	}
//	if(dat & 0x800000){					// output data
//		ADF4001_DAT = 1;
//	}
//	else{
//		ADF4001_DAT = 0;
//	}
//	Nop();								// short delay
//	ADF4001_CLK = 1;					// clock up
//	Nop();								// short delay
	ADF4001_LE = 1;						// Load Enable
	Nop();								// short delay
	Nop();								// short delay
	ADF4001_CLK = 0;					// clock down
	ADF4001_LE = 0;						// Load Disable
}
